package taskmanager;

import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;
import java.util.concurrent.PriorityBlockingQueue;
import mpi.MPIServer;
import mpiserver.IMpiServer;
import mpiserver.MpiServer;
import Network.s2sInnerLogic;
import taskmanager.exception.*;

/**
 * Планировщик задач
 * Единовременно может выполняться только одна задача, остальные ждут в очереди
 * задачам в очереди выставляются приоритеты в зависимости от их состояния
 * Планировщику можно установить режим автподачи задач. Находясь в этом
 * режиме планировщик будет автоматически отправлять задачи на выполнение
 * при появлении такой возможности.
 * Имеется возможность останова системы. Во время останова планировщик
 * прекращает выполнение текущей задачи, но не возвращает её в очередь, при
 * запуске планировщик пытается возобновить выполнение прерваной задачи.
 * Во время останова доступны функции установки активной задачи, послупившие на
 * выполнение задачи будут остановлены до запуска планировщика.
 * @author Volk, Alex-Rude
 * @version alpha
 * @deprecated теперь используется TaskManager
 */
public class JTaskManager implements IJTaskManager
{

    /** ссылка на модуль MPI-сервера */
    private IMpiServer mpiServer = null;
    /** очередь с приоритетами для невыполняемых задач */
    private PriorityBlockingQueue <JTask> waitingTaskQueue = new PriorityBlockingQueue<JTask>();
    /** вектор выполняемых(активных) задач */
    private Vector<JTask> activeTasksVector = new Vector<JTask>();
    /** очередь приостановленных задач */
    private Vector<JTask> stopTasksQueue = new Vector<JTask>();
    /** очередь восстановленных задач */
    private PriorityBlockingQueue<JTask> resumeTasksQueue = new PriorityBlockingQueue<JTask>();
    /** очередь задач по валидации (смотри описании в ПД)*/
    private Vector<JTask> validationTasksQueue = new Stack<JTask>();
    /**максимальное количество одновременно выполняемых задач*/
    private int maxCountActiveTasks = 1;
    /** признак останова системы */
    private boolean systemStoped=true;
    /** признак автоподачи задач */
    private boolean autoTaskServe=true;

    //-------------------------Сервисные методы-----------------------------
    /**
     * Получить активную задачу из списка активных задач
     * @param task - задача с которой происходит сравнение (сравнение происходит по id)
     * @return ссылка на задачу из списка активных задач, null -задачи нет в списке
     */
    private JTask findActiveTask(JTask task){
     for(int i = 0; i < activeTasksVector.size(); i++){
     //Пройтись по всему вектору активных задач в поисках заданной задачи
     JTask temp = activeTasksVector.elementAt(i);
      if(temp.getTaskID() == task.getTaskID())
        return temp;
     }
     return null;
    }

    /**
     * Просканировать очередь активных задач на предмет поиска задачи с эквивалентным исполняемым файлом что и входная задача
     * @return true - найдена эквивалентная задача, false - эквивалентная задача не найдена
     */
    private boolean scanActiveTaskList(JTask task){
      for(JTask temp: activeTasksVector){
        if(temp.getExecFile().equals(task.getExecFile())) return true;
      }
     return false;
    }

    //-------------------------------------------------------------------------

    //--------------------Интерфейсные методы----------------------------------
    /**
     * Установить активную задачу
     * @param task задача
     * @return true в случае успеха, false - активная задача установлена
     * @throws ValidationException - задача не прошла проверку по валидации и была добавлено в очередь валидации
     */
    private boolean setActiveTask(JTask task){
        //проверка состояний системы
        if(task==null)
            throw new NullPointerException("New task can't be a null-value");
        if(activeTasksVector.size() == maxCountActiveTasks) return false;
        //если система остановлена - не выполнять задачу
        if(systemStoped) return false;
        //проверка на валидацию
        if(scanActiveTaskList(task)) {validationTasksQueue.add(task); return false;}
        // Добавляем в вектор запущенных
        activeTasksVector.add(task);
        //task.setActive();
        task.setStatus(JTask.ACTIVE);
        //вызов mpi !!!! -----------------------------------------
        try{
            if(task.isCompiled()) mpiServer.runMpi(task/*, 2*/);
            else mpiServer.runGcc(task);
        }
        catch(Exception e){System.out.println("TASKMANAGER: mpi failed");}
        //--------------------------------------------------------
        return true;
    }

    /**
     * Создание с передачей ссылки на mpiServer параметром
     * @param mpiServer - ссылка на созданный MPI-сервер
     */
    public JTaskManager(IMpiServer mpiServer) {
        this.mpiServer = mpiServer;
    }

    /**
     * Создание планировщика и внутреннего для него модуля MPI-сервера
     */
    public JTaskManager() {}

    /** 
     * Запросить количество задач в очереди
     * @return размер очереди
     */
    public int getTaskQueueSize(){return waitingTaskQueue.size();}
    /**
     * Запросить вектор активных задач
     * @return вектор активных задач
     */

   public Vector<JTask> getActiveTasks(){return (Vector<JTask>)activeTasksVector.clone();}
    /**
     * Проверить наличие хотя бы одной активной задачи
     * @return true - есть активная, false - нет активной задачи
     */
    public boolean hasActiveTask(){
        return !activeTasksVector.isEmpty();
    }
    
    /**
     * Получить текущее количество выполняемых задач
     * @return количество выполняемых задач
    */
    public int getCountActiveTask(){
        return activeTasksVector.size();
    }

    /**
     * проверить наличие задач в очереди
     * @return true если задач нет, иначе false
     */
    public boolean isQueueEmpty(){return waitingTaskQueue.isEmpty();}

    /**
     * Проверить наличие задач выполнение которых было приостановлено
     * @return true - задачи отсутствуют, false - задачи есть
     */
    public boolean isStopTaskQueueEmpty(){return stopTasksQueue.size() == 0?true:false;}

    /**
     * Получить количество остановленных задач
     * @return количество остановленных задач
     */
    public int getCountStopTask(){return stopTasksQueue.size();}

    /**
     * Получить список остановленных задач
     * @return список остановленных задач
     */
    public Vector<JTask> getStopTasks(){
     return new Vector<JTask>(stopTasksQueue);
    }
    
    /**
     * Проверить наличие задач в очереди восстановленных задач
     * @return в очереди имеются задачи
     */
    public boolean hasResumeTasks(){
     return !resumeTasksQueue.isEmpty();
    }

    /**
     * Получить количество восстановленных задач
     * @return количество восстановленных задач
     */
    public int getCountResumeTasks(){return resumeTasksQueue.size();}

    /**
     * Получить список восстановленных задач
     * @return
     */
    public Vector<JTask> getResumeTasks(){return new Vector<JTask>(resumeTasksQueue);}
     /**
     * Получить максимальное количество активных задач
     * @return максимальное количество активных задач
     */
    public int getMaxActiveTasks(){
     return maxCountActiveTasks;
    }

    /**
     * Установить максимальное количество активных задач
     * @param maxCountActiveTasks - максимальное количество активных задач
     * @return true - установка нового значения выполнилось успешно, false - максимальное количество активных задач не может быть меньше 1
     */
    public boolean setMaxActiveTasks(int maxCountActiveTasks){
      if(maxCountActiveTasks < 1) return false;
      this.maxCountActiveTasks = maxCountActiveTasks;
      return true;
    }

    /**
     * добавить задачу в систему
     * в случае, еси включена автоподача задач, очередная задача пойдет на 
     * исполнение
     * @param newTask новая задача
     * @return true в случае успеха, false если задача уже добавлена
     */
    public boolean addTask(JTask newTask){
        if(newTask==null) 
          throw new NullPointerException("New task can't be a null-value");
        //установить задачу на ожидание
        //newTask.setWait();
        newTask.setStatus(JTask.WAITED);
        waitingTaskQueue.add(newTask);
        //если включена автоподача, попытаться отправить на выполнение
        if(autoTaskServe) 
            try{while(activeNextTask());}
            catch(TaskmanagerException e){}
        return true;
    }
    /**
     * Сделать следующую задачу активной
     * @return  true в случае успеха, false - очередь пуста
     * @throws taskmanager.exception.HasActiveTaskException если достигнут лимит одновременно выполняющихся задач
     */
    public boolean activeNextTask() throws HasActiveTaskException{
        //проверка состояний системы
        if(activeTasksVector.size() == maxCountActiveTasks)
            throw new HasActiveTaskException("Task quequ overflow");

       //---------Попробовать отправить на выполнение задачу по валидации----------
        for(int i = 0; i < validationTasksQueue.size(); i++){
         JTask buffer = validationTasksQueue.get(i);
            if(!scanActiveTaskList(buffer)){
               if(setActiveTask(buffer)){
                validationTasksQueue.remove(i);
               }
              return true;
             }else return false;
            }
        //--------------------------------------------------------------------------
        //отправить на выполнение очередную задачу
        boolean isResume = false;
        JTask temp = null;
        boolean isLoop = true;
        while(isLoop){
         if(waitingTaskQueue.isEmpty() && resumeTasksQueue.isEmpty()) return false;

         //Проверить есть ли восстановленные задачи
         if(!resumeTasksQueue.isEmpty()){ 
           temp = resumeTasksQueue.peek();
           isResume = true;
         }else temp = waitingTaskQueue.peek();
         //Проверка задачи на валидацию-------------------------------------------
         if(scanActiveTaskList(temp)){
          if(isResume) resumeTasksQueue.poll();
           else waitingTaskQueue.poll();
          isResume = false;
          validationTasksQueue.add(temp);
         }else isLoop = false;
         //-----------------------------------------------------------------------
        }

        if(setActiveTask(temp)){
         if(isResume) resumeTasksQueue.poll();
          else waitingTaskQueue.poll();
         return true;
        }
        return false;
    }

    /**
     * Остановить активную задачу
     * Активная задача возвращается в очередь и если включена автопоача
     * задач выполняется очередная задача.
     * @return true в случае успеха, false - нет активной задачи
     */
    public boolean stopActiveTask(JTask task){
        JTask activeTask = findActiveTask(task);
        if(activeTask == null) return false;
        //остановить задачу на mpi !!!--------------
        //------------------------------------------
        //activeTask.setStop();
        activeTask.setStatus(JTask.STOPED);
        stopTasksQueue.add(activeTask); //Добавление задачи в очередь приостановленных задач
        activeTasksVector.removeElement(task); // Удалить задачу из списка активных задач
        //если включена автоподача - выполнить следующую задачу
        if(autoTaskServe && !waitingTaskQueue.isEmpty())
         try{activeNextTask();}catch(HasActiveTaskException e){}
        return true;
    }


    /**
     * Запустить активную задачу в случае её приостановки
     * @return true в случае успеха, false - нет активной задачи
     */
    public boolean resumeTask(JTask task){
      if(task == null) throw new NullPointerException();
      //Переместить задачу из очереди приостановленных задач в очередь восстановленных задач
      for(int i = 0; i < stopTasksQueue.size(); i++){
       if(stopTasksQueue.get(i).getTaskID() == task.getTaskID()){
         stopTasksQueue.removeElementAt(i);
         resumeTasksQueue.add(task);
         //task.setWait();
         task.setStatus(JTask.WAITED);
         return true;
       }
      }

      return false;
    }
    /**
     * Проверить останов системы
     * @return true - система остановлена, иначе false
     */
    public boolean isSystemStoped(){ return systemStoped; }
    /**
     * Остановить систему
     * Если есть активная заача она приостанавливается, но не возвращается в
     * очередь
     */
    public void stopSystem(){
        systemStoped=true;
        //Остановить все задачи находящиеся в очереди
        Vector<JTask> activeList = new Vector<JTask>(activeTasksVector);
         for(JTask task : activeList){
           //task.setStop();
           task.setStatus(JTask.STOPED);
           //Вызов модуля MPI с целью приостановления выполнения объекта--------
           //-------------------------------------------------------------------
         }
    }
    /**
     * Запустить систему
     * Если включена автоподача  - пытается запустить задачи из очереди
    */
    public void runSystem(){
        systemStoped=false;
        //если включена автоподача - выполнить очередную задачу
        Vector<JTask> activeList = new Vector<JTask>(activeTasksVector);
         for(JTask task : activeList){
           //task.setActive();
           task.setStatus(JTask.ACTIVE);
           //Вызов модуля MPI с целью восстановления выполнения объекта--------
           //-------------------------------------------------------------------
         }
    }
    
    /**
     * Установить автоматическую подачу задач
     * @param flag признак автоматической подачи
     */
    public void setAutoTaskServe(boolean flag){
        autoTaskServe=flag;
        //если включена автоподача - выполнить очередную задачу
        if(flag)
            try{while(activeNextTask());}
            catch(TaskmanagerException e){}
    }
    /**
     * Запросить признак автоподачи задач
     * @return признак автоподачи задач
     */
    public boolean getAutoTaskServe(){return autoTaskServe;}
    /** Очистить очередь задач */
    public void clearQueue(){waitingTaskQueue.clear();}
    /**
     * Очистить все задачи в системе.
     * Если есть активная задача - она останавливается и удаляется
     */
    public void clearAll(){
        //Остановить все задачи находящиеся в очереди
        while(activeTasksVector.size() != 0)
          stopActiveTask(activeTasksVector.get(0));
        //Очистить все задачи находящиеся в очереди
        waitingTaskQueue.clear();
        //Очистить все задачи находящися в приостановленном состоянии
        stopTasksQueue.clear();
        //Очистить все задачи находящиеся в востановленном состоянии
        resumeTasksQueue.clear();
        //Очистить все задачи непрошедшие валидацию
        validationTasksQueue.clear();
    }
    /**
     * Запросить итератор очереди задач
     * @return итератор
     */
    public Iterator<JTask> getTaskQueueIterator() {
        return waitingTaskQueue.iterator();
    }

    /**
     * Удалить задачу из системы.
     * Если задача активна, выполнение прекращается и заача удаляется,
     * если удалена активная задача и включена автоподача - пытается выполнить
     * очередную задачу
     * @param task задача
     * @return true в случае успеха, false - задачи нет в системе
     */
    public boolean deleteTask(JTask task){
        if(task==null)
            throw new NullPointerException("New task can't be a null-value");
        //если удаляемая задача активна - пректатить выполнение
        if(stopActiveTask(task)){
            //если включена автоподача - выполнять следующую
            if(autoTaskServe)
                try{activeNextTask();}
                catch(TaskmanagerException e){}
        }
        //Осуществляем попытку удаления задачи из одной из очередей
        if(waitingTaskQueue.remove(task)) return true;
        if(validationTasksQueue.remove(task))return true;
        if(stopTasksQueue.remove(task) || resumeTasksQueue.remove(task)){
         //Удаление приостановленного процесса соотвествующего исходной задачи из модуля mpi
         //---------------------------------------------------------------------------------
         return true;
        }

        return false;
    }
    /**
     * Проверить наличие задачи в системе
     * @param task задача
     * @return true если задача присутствует в системе
     */
    public boolean containsTask(JTask task){
        if(task==null)
            throw new NullPointerException("New task can't be a null-value");
        if(activeTasksVector.contains(task)) return true;
        if(stopTasksQueue.contains(task)) return true;
        if(resumeTasksQueue.contains(task)) return true;
        if(validationTasksQueue.contains(task)) return true;
        return waitingTaskQueue.contains(task);
    }
}

